import ctypes
import sys
import time
import os
from common.logger import logger
from common.ToolsKit import ToolsKit
from common.mytSelector import mytSelector
import json
# myt rpc  lib
#   add node oper 2024.1.31
class MytRpc(object):
    # _lib_PATH = "/home/zwj/tiktok/lib/libmytrpc.so"
    # _handle = 0
    def __init__(self) -> None:

        tools = ToolsKit()
        root_path = tools.GetRootPath()
        if sys.platform == "linux":
            #self._lib_PATH = os.path.dirname(os.path.abspath(__file__)) + "/../lib/libmytrpc.so"
            self._lib_PATH = root_path + "/lib/libmytrpc.so"
        else:
            self._lib_PATH = root_path + "/lib/libmytrpc.dll"
             #self._lib_PATH = os.path.dirname(os.path.abspath(__file__)) + "/../lib/libmytrpc.dll"
        self._handle = 0
        # if os.path.exists(self._lib_PATH) == False:
        #     self._lib_PATH = os.path.dirname(os.path.abspath(__file__)) + "/libmytrpc.so"

    def __del__(self) :
        if self._handle>0 :
            self._rpc.closeDevice(self._handle)
    
    #获取SDK 版本
    def get_sdk_version(self):
        ret = ''
        if os.path.exists(self._lib_PATH) == True:
            if sys.platform == "linux":
                dll = ctypes.CDLL(self._lib_PATH)
            else:
                dll = ctypes.WinDLL(self._lib_PATH)

            ret = dll.getVersion()
        return ret

    # 初始化
    def init(self, ip, port, timeout):
        ret = False
        if os.path.exists(self._lib_PATH) == True:
            if sys.platform == "linux":
                self._rpc = ctypes.CDLL(self._lib_PATH)
            else:
                self._rpc = ctypes.WinDLL(self._lib_PATH)
            
            b_time = int(time.time())
            while True:
                self._handle = self._rpc.openDevice(bytes(ip, "utf-8"), port, 10)
                if self._handle > 0:
                    ret = True
                    logger.debug("rpc " + ip + " ok!")
                    break
                else:
                    now = int(time.time())
                    if now-b_time>timeout :
                        logger.debug("rpc " + ip + " timeout " + str(timeout))
                        break
                    else:
                        time.sleep(10)
        else:
            logger.debug("File not Found: " + self._lib_PATH)
        return ret

    #检查远程连接是否处于连接状态
    def check_connect_state(self):
        ret = False
        if self._handle>0:
            self._rpc.checkLive.argtypes = [ctypes.c_long]
            self._rpc.checkLive.restype = ctypes.c_int
            exec_ret = self._rpc.checkLive(self._handle)
            if exec_ret == 0:
                ret = False
            else:
                ret = True
        return ret
            #LIBMYTRPC_API int MYAPI checkLive(long handle);

    # 执行命令
    def exec_cmd(self, cmd):
        ret = False
        if self._handle > 0:
            # cmd = " pm install /data/local/TikTok_26.5.3_apkcombo.com.apk"
            # cmd = "ls"
            self._rpc.execCmd.restype = ctypes.c_char_p
            ptr = self._rpc.execCmd(self._handle, ctypes.c_int(1), ctypes.c_char_p(cmd.encode('utf-8')))
            if ptr is not None:
                if isinstance(ptr, str):
                    ret = ptr.decode('utf-8')
                    logger.debug("exec " + cmd + "  :" + ret)
                else:
                    ret = True
            else:
                ret = True
        return ret

    # 导出节点信息
    # bDumpAll 导出所有节点  0   1
    def dumpNodeXml(self, bDumpAll):
        ret = False
        if self._handle > 0:
                self._rpc.dumpNodeXml.argtypes = [ctypes.c_long, ctypes.c_int]
                self._rpc.dumpNodeXml.restype = ctypes.c_void_p
                ptr = self._rpc.dumpNodeXml(self._handle, bDumpAll)
                p2 = ctypes.cast(ptr, ctypes.c_char_p)
                try:
                    ret = p2.value.decode("utf-8")
                    # 释放指针内存
                    self._rpc.freeRpcPtr.argtypes = [ctypes.c_void_p]
                    self._rpc.freeRpcPtr(ptr)
                except Exception as e:
                    print("e",e)
                    return False
        return ret

    # 截图导出为bytes 数组
    # type  0 png  1 jpg
    # quality  图片质量  0-100
    # 返回字节数组
    def takeCaptrueCompress(self, type, quality):
        ret = False
        if self._handle > 0:
            dataLen = ctypes.c_int(0)
            self._rpc.takeCaptrueCompress.argtypes = [ctypes.c_long, ctypes.c_int, ctypes.c_int,  ctypes.POINTER(ctypes.c_int)]
            self._rpc.takeCaptrueCompress.restype = ctypes.c_void_p
            ptr = self._rpc.takeCaptrueCompress(self._handle, type, quality, ctypes.byref(dataLen))
            if ptr:
                try:
                    # 将ptr转换为bytes对象
                    buf = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_ubyte * dataLen.value)).contents
                    # 使用OpenCV将bytes对象转换为图像
                    ret = bytearray(buf)
                    # img_np = np.frombuffer(img_array, dtype=np.uint8)
                    # img = cv2.imdecode(img_np, cv2.IMREAD_COLOR)
                    # # 显示图像
                    # cv2.imshow("Image", img)
                    # cv2.waitKey(0)
                finally:
                    # 释放指针内存
                    self._rpc.freeRpcPtr.argtypes = [ctypes.c_void_p]
                    self._rpc.freeRpcPtr(ptr)
        return ret
    
    #截图到文件
    def screentshot(self, type, quality, file_path):
        ret = False
        byte_data = self.takeCaptrueCompress(type, quality) 
        if byte_data != False:
            with open(file_path, 'wb') as file:
                file.write(byte_data)
            ret = True
        return ret

    # 文字输入
    def sendText(self, text):
        ret = False
        if self._handle > 0:
            exec_ret =  self._rpc.sendText(self._handle, ctypes.c_char_p(text.encode('utf-8')))
            if exec_ret == 1:
                ret = True
        return ret

    #清除输入的文字
    def ClearText(self, count):
        for i in range(0, count):
            self.keyPress(67)
        


    # 开启指定的应用
    def openApp(self, pkg):
        ret = False
        if self._handle > 0:
            exec_ret = self._rpc.openApp(self._handle, ctypes.c_char_p(pkg.encode('utf-8')))
            if exec_ret == 1:
                ret = True
        return ret

    #停止指定的应用
    def stopApp(self, pkg):
        ret = False
        if self._handle > 0:
            exec_ret = self._rpc.stopApp(self._handle, ctypes.c_char_p(pkg.encode('utf-8')))
            if exec_ret == 1:
                ret = True
        return ret

    #获取当前屏幕的方向
    #  4个方向（0,1,2,3）
    def getDisplayRotate(self):
        ret = False
        if self._handle > 0:
            if self._rpc.getDisplayRotate(self._handle) == 1:
                ret = True
        return ret
    
    #按下操作
    def touchDown(self, finger_id, x, y):
        ret = False
        if self._handle > 0:
            if self._rpc.touchDown(self._handle, finger_id, x, y) == 1:
                ret = True
        return ret
    
    #弹起操作
    def touchUp(self, finger_id, x, y):
        ret = False
        if self._handle > 0:
            if self._rpc.touchUp(self._handle, finger_id, x, y) == 1:
                ret = True
        return ret
    
    #滑动操作
    def touchMove(self, finger_id, x, y):
        ret = False
        if self._handle > 0:
            if self._rpc.touchMove(self._handle, finger_id, x, y) == 1:
                ret = True
        return ret
    
    #单击操作
    def touchClick(self, finger_id, x, y):
        ret = False
        if self._handle > 0:
            if self._rpc.touchClick(self._handle, finger_id, x, y) == 1:
                ret = True
        return ret

    #长按操作
    #t 为长按的时长  单位: 秒(float)
    def longClick(self, finger_id, x, y, t):
        ret = False
        if self._handle>0:
            if self._rpc.touchDown(self._handle, finger_id, x, y) > 0:
                time.sleep(t)
                exec_ret = self._rpc.touchUp(self._handle, finger_id, x, y)
                if exec_ret ==1 :
                    ret = True
        return ret

    #按键操作
    # 键值 参考: https://blog.csdn.net/yaoyaozaiye/article/details/122826340
    def keyPress(self, code):
        ret = False
        if self._handle > 0:
            if self._rpc.keyPress(self._handle, code) == 1:
                ret = True
        return ret
    
    #Back按键
    def pressBack(self):
        return self.keyPress(4)
    
    #Enter 按键
    def pressEnter(self):
        return self.keyPress(66)
    
    #Home 按键
    def pressHome(self):
        return self.keyPress(3)
    
    #Menu 按键
    def pressRecent(self):
        return self.keyPress(82)

    #滑动操作
    # x0 y0 起始坐标
    # x1 y1 终点坐标
    # elapse 时长  (单位:毫秒)   
    def swipe(self, id, x0, y0, x1, y1, elapse):
        ret = False
        if self._handle>0:
            ret = self._rpc.swipe(self._handle,id,  x0, y0, x1, y1, elapse, False)
        return ret
    
    #创建selector筛选器对象
    def create_selector(self):
        ret = None
        if self._handle>0:
            ret = mytSelector(self._handle, self._rpc)
        return ret
    
    #释放 selector 对象
    def release_selector(self, sel):
        del sel
    
    #按照Node的属性执行点击
    def clickText(self, text):
        ret = False
        selector = self.create_selector() 
        selector.addQuery_TextEqual(text)
        node = selector.execQueryOne(200)
        if node is not None:
            ret = node.Click_events()
        self.release_selector(selector)
        return ret
        
    def clickClass(self, clzName):
        ret = False
        selector = self.create_selector() 
        selector.addQuery_ClzEqual(clzName)
        node = selector.execQueryOne(200)
        if node is not None:
            ret = node.Click_events()
        self.release_selector(selector)
        return ret
    
    def clickId(self, id):
        ret = False
        selector = self.create_selector() 
        selector.addQuery_IdEqual(id)
        node = selector.execQueryOne(200)
        if node is not None:
            ret = node.Click_events()
        self.release_selector(selector)
        return ret
    
    def clickDesc(self, des):
        ret = False
        selector = self.create_selector() 
        selector.addQuery_DescEqual(des)
        node = selector.execQueryOne(200)
        if node is not None:
            ret = node.Click_events()
        self.release_selector(selector)
        return ret

    #依据Text 获取Node节点
    def getNodeByText(self, text):
        ret  = None
        selector = self.create_selector() 
        selector.addQuery_TextEqual(text)
        node_arr = selector.execQuery(999,200)
        if len(node_arr)>0 :
            arr = []
            for n in node_arr:
                json_str = n.getNodeJson()
                json_obj = json.loads(json_str)
                arr.append(json_obj)
            ret = json.dumps(arr)
        self.release_selector(selector)
        return ret
    
    def getNodeByClass(self, clzName):
        ret  = None
        selector = self.create_selector() 
        selector.addQuery_ClzEqual(clzName)
        node_arr = selector.execQuery(999,200)
        if len(node_arr)>0 :
            arr = []
            for n in node_arr:
                json_str = n.getNodeJson()
                json_obj = json.loads(json_str)
                arr.append(json_obj)
            ret = json.dumps(arr)
        self.release_selector(selector)
        return ret

    def getNodeById(self, id):
        ret  = None
        selector = self.create_selector() 
        selector.addQuery_IdEqual(id)
        node_arr = selector.execQuery(999,200)
        if len(node_arr)>0 :
            arr = []
            for n in node_arr:
                json_str = n.getNodeJson()
                json_obj = json.loads(json_str)
                arr.append(json_obj)
            ret = json.dumps(arr)
        self.release_selector(selector)
        return ret
    
    def getNodeByDesc(self, desc):
        ret  = None
        selector = self.create_selector() 
        selector.addQuery_DescEqual(desc)
        node_arr = selector.execQuery(999,200)
        if len(node_arr)>0 :
            arr = []
            for n in node_arr:
                json_str = n.getNodeJson()
                json_obj = json.loads(json_str)
                arr.append(json_obj)
            ret = json.dumps(arr)
        self.release_selector(selector)
        return ret